<template>
  <div ref="popover" class="popover" @click.stop="showChange">
    <div v-if="show" id="popover-content" ref="contentWrapper" class="content-wrapper">
      <slot name="content"></slot>
    </div>
    <span ref="triggerWrapper">
      <slot></slot>
    </span>
  </div>
</template>

<script lang="ts" setup>
import { ref, nextTick, onBeforeUnmount } from 'vue'

const emits = defineEmits(['change'])

const show = ref(false)
const popover = ref()
const contentWrapper = ref()
const triggerWrapper = ref()

const position = () => {
  document.body.appendChild(contentWrapper.value)
  const { left, top } = triggerWrapper.value.getBoundingClientRect()
  contentWrapper.value.style.top = top + scrollY - 10 + 'px'
  contentWrapper.value.style.left = left - 150 + scrollX + 'px'
}
const listener = (event) => {
  if ((popover.value && popover.value.contains(event.target)) || popover.value === event.target) {
    return
  }
  if ((contentWrapper.value && contentWrapper.value.contains(event.target)) || contentWrapper.value === event.target) {
    return
  }
  close()
  emits('change', show.value)
}
const close = () => {
  show.value = false
  document.removeEventListener('click', listener)
}
const open = () => {
  show.value = true
  nextTick(() => {
    position()
    document.addEventListener('click', listener)
  })
}
const showChange = (event) => {
  if (triggerWrapper.value.contains(event.target)) {
    if (show.value === true) {
      close()
    } else {
      open()
    }
    emits('change', show.value)
  }
}
onBeforeUnmount(() => {
  close()
  // 如果无法移除就手动移除
  const popoverContent = document.getElementById('popover-content')
  if (popoverContent) {
    document.body.removeChild(popoverContent)
  }
})
</script>

<style lang="less" scoped>
.popover {
  display: inline-block;
  position: relative;
}

.content-wrapper {
  position: absolute;
  padding: 16px;
  border: 1px solid #ebeef5;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  background: white;
  transform: translateY(-100%);
  z-index: 999999;
  border-radius: 8px;
}
</style>
